import os
import tornado.ioloop
import tornado.web,time

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("""<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>File Download</title>
</head>
<body>
  <button id="download-btn">Download File</button>
  <div id="status"></div>

  <script>function generateRandomString(length) {  
    const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';  
    let result = '';  
    const charactersLength = characters.length;  
    for (let i = 0; i < length; i++) {  
        const randomIndex = Math.floor(Math.random() * charactersLength);  
        result += characters[randomIndex];  
    }  
    return result;  
}  
document.getElementById('download-btn').addEventListener('click', async () => {
                   
    const response = await fetch('/download/'+generateRandomString(10));
    const data = await response.json();

    if (data.type === 'wait') {
      console.log("wait",data.num)
    }else if(data.type=='ok'){
      window.location.href = '/start_download/'+data.down_id;
                 
                 }
    return
    }
  );
  </script>
</body>
</html>
""")
count=0
file_path =r'E:\my\easy_edit\_static_dir\font_test\demo.css'
class DownloadHandler(tornado.web.RequestHandler):
    async def get(self, file_name):
        
        if file_name not in ['example.txt']:
            raise tornado.web.HTTPError(404)
        self.set_header('Content-Type', 'application/octet-stream')
        self.set_header('Content-Disposition', f'attachment; filename={file_name}')
        
        file_path =r'C:\Users\Administrator\Downloads\Mind+_Win_V1.7.3_RC3.0 (1).exe'
        with open(file_path, 'rb') as f:
            while True:
                chunk = f.read(16*1024)
                if not chunk: break
                await self.write(chunk)
            await self.finish()
import aiofiles  
import tornado.ioloop  
import tornado.web  
#当前正在下载的
now_down_dct={

}
now_down_lst=[]
#限制最大下载量
now_down_max=4
#最大等待下载数量
now_wait_max=200
#正在排队下载的
now_wait_lst=[]
#最大超时未下载时间(超出则清除)
max_time=10
class DownloadHandler(tornado.web.RequestHandler):  
    async def get(self,request_id):  
        down_id=request_id
        #如果超过最大排队数量 直接返回需要等待 now_wait_max+
        if len(now_wait_lst)>now_wait_max:
            print("等待",now_wait_max,'+')
            self.write({"type":"wait","num":str(now_wait_max)+'+'})
            return
        #加入待下载列表
        now_time=time.time()
        now_wait_lst.append({"id":down_id,"time":now_time})

        #清除超时未请求下载数据
        while len(now_wait_lst):
            if now_wait_lst[0]['time']+max_time<now_time:
                now_wait_lst.pop(0)
            else:
                break
        # print("如果当前不处在排队第一位置 那么返回需要等待 now_wait_max")
        if now_wait_lst[0]['id']!=down_id:
            print("等待",len(now_wait_lst))
            self.write({"type":"wait","num":len(now_wait_lst)})
            return
        # print("如果正在下载的数量已达到最大 那么返回需要等待 1")
        if len(now_down_dct.keys())>=now_down_max:
            print("等待",'1')
            self.write({"type":"wait","num":'1'})
            return
        # print("清除自身在待下载队列的信息 存储入正在下载队列")
        wait_obj=now_wait_lst.pop(0)
        now_down_dct[wait_obj['id']]=wait_obj
        # print("返回可以下载信号")
        self.write({"type":"ok","down_id":down_id})
        return

class start_download(tornado.web.RequestHandler):  
    async def get(self,request_id):  
        
        print("下载",len(now_down_dct.keys()))
        self.set_header('Content-Type', 'application/zip')  
        self.set_header('Content-Disposition', 'attachment; filename="file.zip"')  
        async with aiofiles.open(file_path, 'rb') as f:  
            while True:  
                chunk = await f.read(4096)  # 异步读取文件块  
                if not chunk:  
                    break  
                self.write(chunk)  
                try:
                    await self.flush()  # 确保数据被发送到客户端  
                except:
                    break
        del now_down_dct[request_id]
        self.finish()



def make_app():
    return tornado.web.Application([
        (r"/", MainHandler),
        (r"/download/(.*)", DownloadHandler),
        (r"/start_download/(.*)", start_download),
    ])

if __name__ == "__main__":
    app = make_app()
    app.listen(8888)
    print("Server started on port 8888")
    tornado.ioloop.IOLoop.current().start()
